<html>
    <head>
        <title>额外属性 和 对象扩展管理系统</title>
    </head>
    <body>
        <script>
            /*
                     八、额外属性 和 对象扩展管理器  Extra Properties & Object Extension Manager

                                Extra Properties系统允许你为实现IHasExtraProperties接口的实体设置/获取动态属性。

                                当你想将"自定义属性" 添加到依赖的应用程序模块中定义的实体时，当你将模块用作包引用时，它特别有用。

                                "默认"情况下，实体的"所有额外属性"都存储为数据库中的"单个JSON对象"。

                                实体扩展系统允许你将所需的额外属性存储在相关数据库表的单独字段中。
                                
                                有关额外属性和实体扩展系统的更多信息，请参阅以下文档：

                                    ①、自定义应用程序模块：扩展实体   https://abp.io/docs/latest/framework/architecture/modularity/extending/customizing-application-modules-extending-entities

                                    ②、Entities 实体   https://abp.io/docs/latest/framework/architecture/domain-driven-design/entities


                            1、ObjectExtensionManager.Instance 对象扩展管理器实例

                                    ObjectExtensionManager实现单例模式，因此需要使用静态ObjectExtensionManager.Instance来执行所有操作。
    
                                    ObjectExtensionManager.Instance 用来访问对象扩展管理器的唯一实例。

                            2、MapEfCoreProperty  （映射额外属性）

                                    MapEfCoreProperty是一种快捷扩展方法，用于定义实体的扩展属性并映射到数据库。

                                    eg:  将Title属性（数据库字段）添加到IdentityRole实体：

                                         ObjectExtensionManager.Instance
                                                                .MapEfCoreProperty<IdentityRole, string>(
                                                                    "Title",
                                                                    (entityBuilder, propertyBuilder) =>
                                                                    {
                                                                        propertyBuilder.HasMaxLength(64);
                                                                    }
                                                                );

                            3、MapEfCoreEntity  （映射某个实体类型的额外属性）

                                    MapEfCoreEntity是配置Entity的快捷扩展方法。、

                                    eg： 设置IdentityRole实体的Name属性最大长度为200

                                            ObjectExtensionManager.Instance
                                                                    .MapEfCoreEntity<IdentityRole>(builder =>
                                                                    {
                                                                        builder.As<EntityTypeBuilder<IdentityRole>>().Property(x => x.Name).HasMaxLength(200);
                                                                    });


                            4、MapEfCoreDbContext  (映射某个DbContext上的实体、属性配置)

                                    MapEfCoreDbContext是配置DbContext的快捷扩展方法。

                                    eg：设置IdentityDbContext 中的IdentityRole实体的Name属性最大长度为200：

                                            ObjectExtensionManager.Instance.MapEfCoreDbContext<IdentityDbContext>(b =>
                                            {
                                                b.Entity<IdentityRole>().Property(x => x.Name).HasMaxLength(200);
                                            });


                            如果相关模块已经实现了此功能（如下所述），则将新属性添加到模型或更改DbContext/Entity配置。

                            然后你需要运行标准的Add-Migration和Update-Database命令来更新你的数据库以添加新字段。


                                        

                            5、ConfigureEfCoreEntity、ApplyObjectExtensionMappings 和TryConfigureObjectExtensions

                                    如果你正在构建可重用模块并希望允许应用程序开发人员向你的实体添加属性，
                                    
                                    你可以在实体映射中使用ConfigureEfCoreEntity、ApplyObjectExtensionMappings和TryConfigureObjectExtensions扩展方法。
                                
                                    eg：
                                        public static class QADbContextModelCreatingExtensions
                                        {
                                            public static void ConfigureQA(
                                                this ModelBuilder builder,
                                                Action<QAModelBuilderConfigurationOptions> optionsAction = null)
                                            {
                                                Check.NotNull(builder, nameof(builder));

                                                var options = new QAModelBuilderConfigurationOptions(
                                                    QADatabaseDbProperties.DbTablePrefix,
                                                    QADatabaseDbProperties.DbSchema
                                                );

                                                optionsAction?.Invoke(options);

                                                builder.Entity<QA_Question>(b =>
                                                {
                                                    b.ToTable(options.TablePrefix + "Questions", options.Schema);
                                                    b.ConfigureByConvention();
                                                    //...

                                                    //在 build操作后调用ApplyObjectExtensionMappings方法
                                                    b.ApplyObjectExtensionMappings();
                                                });

                                                //...

                                                //Call this in the end of ConfigureQA.
                                                builder.TryConfigureObjectExtensions<QADbContext>();
                                            }
                                        }

                                  如果你调用ConfigureByConvention()扩展方法（如本例中的b.ConfigureByConvention()），ABP会在内部调用ConfigureObjectExtensions和ConfigureEfCoreEntity方法。

                                  使用ConfigureByConvention()方法是的最佳实践，因为它还按照约定为基本属性配置数据库映射。
                                                    
                */
        </script>
    </body>
</html>